Skip to content

[SPARK-58322][CORE] Verify executor app ID at registration time#57525

Open
wangyum wants to merge 2 commits into
apache:masterfrom
wangyum:SPARK-58322
Open

[SPARK-58322][CORE] Verify executor app ID at registration time#57525
wangyum wants to merge 2 commits into
apache:masterfrom
wangyum:SPARK-58322

Conversation

@wangyum

@wangyum wangyum commented Jul 25, 2026

Copy link
Copy Markdown
Member

What changes were proposed in this pull request?

This PR adds an appId field to the RegisterExecutor RPC message and validates it in DriverEndpoint.receiveAndReply against scheduler.sc.applicationId. The executor sends env.conf.getAppId (which is the --app-id launch argument) in RegisterExecutor. On mismatch, the driver rejects the registration with a SparkException.

appId defaults to null in RegisterExecutor for backward compatibility with custom/external cluster managers that construct the message without it. Option(appId).exists(_ != scheduler.sc.applicationId) cleanly skips the check when appId is null.

Why are the changes needed?

When a driver hits a fatal error (e.g., OOM) that kills the RPC dispatcher thread, SparkContext.stop() releases the driver's RPC port while the driver process (and in YARN cluster mode, the ApplicationMaster) can remain in a zombie state — still heartbeating to the resource manager but effectively dead. During this window, the freed port can be rebound by another driver on the same host, and newly launched executors can connect to the wrong driver and register to the wrong application, risking data corruption.

Does this PR introduce any user-facing change?

Yes. In the rare case of an app-ID mismatch at registration, the executor will now be rejected by the driver instead of registering to the wrong application. The error message is:

Executor app ID <appId> does not match driver app ID <driverAppId>.
This likely means the executor connected to the wrong driver.

No config or API changes. No impact on normal operation. External cluster managers that do not set appId in RegisterExecutor are unaffected (the check is skipped).

How was this patch tested?

Unit tests in CoarseGrainedSchedulerBackendSuite:

  • SPARK-58322: reject RegisterExecutor with mismatched app ID — verifies mismatch is rejected
  • SPARK-58322: accept RegisterExecutor with matching app ID — verifies match is accepted
  • SPARK-58322: accept RegisterExecutor with null app ID for backward compatibility — verifies null appId is accepted
  • SPARK-58322: reject RegisterExecutor after driver swap between config fetch and registration — simulates the port-reuse scenario: config fetched from a fake driver A, then RegisterExecutor sent to real driver B, verifies rejection

Was this patch authored or co-authored using generative AI tooling?

Generated-by: GLM 5.2.

@uros-b

uros-b commented Jul 26, 2026

Copy link
Copy Markdown
Member

Thank you @wangyum!

@sunchao sunchao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two application-identity races can still allow an executor to register with the wrong driver. The inline comments describe the startup-cached missing-ID case and the config-fetch-versus-registration connection race.

}

val cfg = driver.askSync[SparkAppConfig](RetrieveSparkAppConfig(arguments.resourceProfileId))
verifyAppId(cfg.sparkProperties, arguments.appId)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Validate the application ID on the registration connection

This checks the driver identity only on driverPropsFetcher, but that RPC environment is shut down immediately afterwards. The executor subsequently creates a new SparkEnv, resolves driverUrl again in CoarseGrainedExecutorBackend.onStart, and sends RegisterExecutor on a different connection. RegisterExecutor contains no application ID, and DriverEndpoint accepts an otherwise valid, previously unused executor ID. Consequently, if the verified driver releases its port and a different application's driver binds the same address between config retrieval and registration, the executor still registers with the wrong application despite this check. This reproduces the port-reuse/data-corruption scenario the PR is intended to prevent under the default RPC authentication settings; the Kubernetes backend has the same two-connection sequence. Please include the executor's application ID in RegisterExecutor and validate it in DriverEndpoint, or otherwise bind the identity check to the connection used for registration. Add a regression test that swaps the driver between config retrieval and registration.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. fix this issue

private[spark] def verifyAppId(
sparkProperties: Seq[(String, String)],
executorAppId: String): Unit = {
sparkProperties.find(_._1 == "spark.app.id").map(_._2).foreach { driverAppId =>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Do not accept an application ID missing from the driver's cached configuration

DriverEndpoint.sparkProperties is an immutable lazy val, initialized by the first RetrieveSparkAppConfig request. However, SparkContext calls _taskScheduler.start() before _conf.set("spark.app.id", _applicationId), and the standalone scheduler can launch an executor during that startup. If the first executor fetches its config in this window, the cached driver properties omit spark.app.id for the entire application lifetime. This .find(...).foreach then silently succeeds for every later executor, including one belonging to another application, so the proposed protection is permanently disabled. The new appId verification no-op when spark.app.id absent test actually codifies this failure. Please obtain the finalized application ID from an authoritative driver/scheduler source and reject an unverifiable identity, ideally in the registration handler; add a regression test that fetches configuration before the driver publishes its application ID.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. fix this issue

…tion

Add appId to RegisterExecutor message and validate it in DriverEndpoint
against scheduler.sc.applicationId. This binds the identity check to the
registration connection itself, preventing the config-fetch-vs-registration
race where a wrong driver could bind the same port between config retrieval
and registration.

The check replaces the executor-side verifyAppId which ran on a transient
RPC connection that was shut down before registration. The driver-side check
is authoritative since scheduler.sc.applicationId is always set before any
executor can register.

Null appId is accepted for backward compatibility with custom/external
cluster managers that construct RegisterExecutor without appId.
@wangyum wangyum changed the title [SPARK-58322][CORE] Verify executor app ID matches driver at config fetch [SPARK-58322][CORE] Verify executor app ID at registration time Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants